package com.star.common.kit.date;

import cn.hutool.core.date.DatePattern;
import com.star.common.kit.constant.DatePatternConstants;
import com.star.common.kit.lang.StrPoolUtils;
import org.apache.commons.lang3.StringUtils;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjusters;
import java.util.Date;

/**
 * LocalDate 和 LocalDateTime操作的工具类
 * JDK 1.8 时间线程安全，api丰富，不需要包装过多的工具类操作，很多操作自带了。
 * LocalDate or LocalDateTime 自带的 api：
 * <pre>
 *     now() 获取当前时间
 *     parse(时间) 根据 format 将字符串时间转换为 LocalDate or LocalDateTime
 *     format(format) 根据 format 将 LocalDate or LocalDateTime 转换为字符串时间
 *     isBefore 当前时间在另一个时间之前
 *     isAfter 当前时间在另一个时间之后
 *     compareTo 比较两个时间的大小 -1 当前时间小于另一个时间；0 相等；1 当前时间大于另一个时间；
 *     isEqual 比较两个时间是否相等
 *     minusDays 获取N天前的时间；获取N天后的时间为 plusDays；
 *     minusWeeks 获取N周前的时间； 获取N天后的时间为 plusWeeks；
 *     minusMonths 获取N月前的时间； 获取N天后的时间为 plusMonths；
 *     minusYears 获取N年前的时间；获取N天后的时间为 plusYears；
 *     Duration.between(date1, date2) 两个时间之间的操作，可以获取相差几天、小时、分钟、毫秒、纳秒
 *     getDay、getDayOfWeek、getDayOfMonth、getDayOfYear、getMonth、getYear 获取当前时间的年月日周
 *     toInstant(时区 ZoneOffset.of("+8") ).toEpochMilli() 时间戳，毫秒级，需要时区，
 *     toEpochSecond(时区 ZoneOffset.of("+8") )时间戳，秒级，需要时区，
 *     LocalDate.toString() 结果为 yyyy-MM-dd；LocalDateTime.toString() 结果为 yyyy-MM-ddTHH:mm:ss 的时间字符串
 * </pre>
 *
 * @author: zhouhengzhe
 */
public class DateUtil {

    /**
     * 时间戳纳秒级别
     */
    private static long referenceNanoTime = System.nanoTime();
    /**
     * 时间戳毫秒级别
     */
    private static long referenceMilliTime = System.currentTimeMillis();
    /**
     * 无符号分隔的时分秒时间格式 HHmmss
     */
    public static final DateTimeFormatter TIME_FORMAT1 = DateTimeFormatter.ofPattern(DatePattern.PURE_TIME_PATTERN);
    /**
     * “ : ” 符号分隔的时分秒时间格式 HH:mm:ss
     */
    public static final DateTimeFormatter TIME_FORMAT2 = DateTimeFormatter.ofPattern(DatePattern.NORM_TIME_PATTERN);
    /**
     * 无符号分隔的年月时间格式 yyyyMM
     */
    public static final DateTimeFormatter DATE_FORMAT1 = DateTimeFormatter.ofPattern(DatePattern.SIMPLE_MONTH_PATTERN);
    /**
     * 无符号分隔的年月日时间格式 yyyyMMdd
     */
    public static final DateTimeFormatter DATE_FORMAT2 = DateTimeFormatter.ofPattern(DatePattern.PURE_DATE_PATTERN);
    /**
     * “ - ” 符号分隔的年月时间格式 yyyy-MM
     */
    public static final DateTimeFormatter DATE_FORMAT3 = DateTimeFormatter.ofPattern(DatePattern.NORM_MONTH_PATTERN);
    /**
     * “ - ” 符号分隔的年月日时间格式 yyyy-MM-dd
     */
    public static final DateTimeFormatter DATE_FORMAT4 = DateTimeFormatter.ofPattern(DatePattern.NORM_DATE_PATTERN);
    /**
     * “ / ” 符号分隔的年月时间格式 yyyy/MM
     */
    public static final DateTimeFormatter DATE_FORMAT5 = DateTimeFormatter.ofPattern(DatePatternConstants.EN_DATE_MONTH_PATTERN);
    /**
     * “ / ” 符号分隔的年月日时间格式 yyyy/MM/dd
     */
    public static final DateTimeFormatter DATE_FORMAT6 = DateTimeFormatter.ofPattern(DatePatternConstants.EN_DATE_PATTERN);
    /**
     * “ / ” 符号分隔的月日年时间格式 MM/dd/yyyy
     */
    public static final DateTimeFormatter DATE_FORMAT7 = DateTimeFormatter.ofPattern(DatePatternConstants.ZH_DATE_PATTERN);

    /**
     * 无符号分隔的年月日时分秒时间格式 yyyyMMddHHmmss
     */
    public static final DateTimeFormatter DATE_TIME_FORMAT1 = DateTimeFormatter.ofPattern(DatePattern.PURE_DATETIME_PATTERN);
    /**
     * 无符号分隔的年月日 “ : ” 符号分隔的时分秒时间格式 yyyyMMdd HH:mm:ss
     */
    public static final DateTimeFormatter DATE_TIME_FORMAT2 = DateTimeFormatter.ofPattern(DatePatternConstants.DATE_TIME_FORMAT2);
    /**
     * “ - ” 符号分隔的年月日 “ : ” 符号分隔的时分时间格式 yyyy-MM-dd HH:mm
     */
    public static final DateTimeFormatter DATE_TIME_FORMAT3 = DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_MINUTE_PATTERN);
    /**
     * “ - ” 符号分隔的年月日 “ : ” 符号分隔的时分秒时间格式 yyyy-MM-dd HH:mm:ss
     */
    public static final DateTimeFormatter DATE_TIME_FORMAT4 = DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN);
    /**
     * “ / ” 符号分隔的年月日 “ : ” 符号分隔的时分秒时间格式 yyyy/MM/dd HH:mm:ss
     */
    public static final DateTimeFormatter DATE_TIME_FORMAT5 = DateTimeFormatter.ofPattern(DatePatternConstants.EN_DATETIME_PATTERN);
    /**
     * 标准的 ISO 年月日时分秒时间格式 yyyy-MM-dd'T'HH:mm:ss
     */
    public static final DateTimeFormatter DATE_TIME_FORMAT6 = DateTimeFormatter.ofPattern(DatePattern.UTC_SIMPLE_PATTERN);
    /**
     * 标准的 ISO 年月日时分秒时间格式 yyyy-MM-dd HH:mm:ss.S
     */
    public static final DateTimeFormatter DATE_TIME_FORMAT7 = DateTimeFormatter.ofPattern(DatePatternConstants.DATE_TIME_FORMAT7);
    /**
     * “ - ” 符号分隔的年月日 “ : ” 符号分隔的时分秒毫秒时间格式 yyyy-MM-dd HH:mm:ss.SSS
     */
    public static final DateTimeFormatter DATE_TIME_FORMAT8 = DateTimeFormatter.ofPattern(DatePatternConstants.DATE_TIME_FORMAT8);
    /**
     * 标准的 ISO 年月日时分秒毫秒时间格式 yyyy-MM-dd'T'HH:mm:ss.SSS
     */
    public static final DateTimeFormatter DATE_TIME_FORMAT9 = DateTimeFormatter.ofPattern(DatePattern.UTC_SIMPLE_MS_PATTERN);


    /**
     * String 转Date
     */
    public static Date stringToDate(String dateStr, String pattern) {
        SimpleDateFormat sdf = new SimpleDateFormat(pattern);
        //存明细表的值
        try {
            return sdf.parse(dateStr);
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 获取指定格式的当前时间
     */
    public static Date getCurrentDate(String pattern) {
        return stringToDate(dateToString(new Date(), pattern), pattern);
    }
    /**
     * Date 转String
     */
    public static String dateToString(Date date, String pattern) {
        SimpleDateFormat sdf = new SimpleDateFormat(pattern);
        return sdf.format(date);
    }

    /**
     * 两时间比较
     */
    public static int compareDate(Date date1, Date date2) {
        return date1.compareTo(date2);
    }
    /**
     * LocalDate按指定格式转Date
     */
    public static Date localDateToDate(LocalDate localDate, String pattern) {
        return stringToDate(localDate.format(DateTimeFormatter.ofPattern(pattern)), pattern);
    }
    /**
     * 根据传入的时间格式格式化字符串
     *
     * @param dateStr           时间格式的字符串
     * @param dateTimeFormatter 格式化模板
     * @return LocalDate
     */
    public static LocalDate parseLocalDate(String dateStr, DateTimeFormatter dateTimeFormatter) {
        return LocalDate.parse(dateStr, dateTimeFormatter);
    }

    /**
     * 根据传入的时间格式格式化字符串
     *
     * @param dateStr           时间格式的字符串
     * @param dateTimeFormatter 格式化模板
     * @return LocalDateTime
     */
    public static LocalDateTime parseLocalDateTime(String dateStr, DateTimeFormatter dateTimeFormatter) {
        return LocalDateTime.parse(dateStr, dateTimeFormatter);
    }

    /**
     * 将LocalDate转换为固定格式的字符串
     *
     * @param localDate         时间
     * @param dateTimeFormatter 格式化模板
     * @return
     */
    public static String localDateToStr(LocalDate localDate, DateTimeFormatter dateTimeFormatter) {
        return localDate.format(dateTimeFormatter);
    }

    /**
     * 将LocalDateTime转换为固定格式的字符串
     * 支持的标准时间格式为：yyyyMMdd、yyyy-MM-dd、yyyy/MM/dd、yyyyMMddHHmmss、yyyy-MM-dd HH:mm:ss、yyyy/MM/dd HH:mm:ss
     *
     * @param localDateTime     时间
     * @param dateTimeFormatter 格式化模板
     * @return
     */
    public static String localDateTimeToStr(LocalDateTime localDateTime, DateTimeFormatter dateTimeFormatter) {
        if (localDateTime == null) {
            return null;
        }
        return localDateTime.format(dateTimeFormatter);
    }

    /**
     * 将时间格式的字符串转换成 LocalDate
     * 支持的标准时间格式为：yyyyMMdd、yyyy-MM-dd、yyyy/MM/dd、yyyyMMddHHmmss、yyyy-MM-dd HH:mm:ss、yyyy/MM/dd HH:mm:ss
     *
     * @param dateStr 时间格式的字符串
     * @return LocalDate
     */
    public static LocalDate parseLocalDate(String dateStr) {
        if (StringUtils.isEmpty(dateStr)) {
            return null;
        }
        LocalDate localDate;
        // “ - ” 符号分隔的年月日时间格式
        if (dateStr.contains(StrPoolUtils.DASH)) {
            if (dateStr.contains(StringUtils.SPACE)) {
                localDate = LocalDateTime.parse(dateStr, DATE_TIME_FORMAT4).toLocalDate();
            } else {
                localDate = LocalDate.parse(dateStr, DATE_FORMAT4);
            }
        }
        // “ / ” 符号分隔的年月日时间格式
        else if (dateStr.contains(StrPoolUtils.SLASH)) {
            if (dateStr.contains(StringUtils.SPACE)) {
                localDate = LocalDateTime.parse(dateStr, DATE_TIME_FORMAT5).toLocalDate();
            } else {
                localDate = LocalDate.parse(dateStr, DATE_FORMAT6);
            }
        }
        // 无符号分隔的年月日时间格式
        else {
            if (dateStr.length() == 14) {
                localDate = LocalDateTime.parse(dateStr, DATE_TIME_FORMAT1).toLocalDate();
            } else {
                localDate = LocalDate.parse(dateStr, DATE_FORMAT2);
            }
        }
        return localDate;
    }

    /**
     * 将时间格式的字符串转换成 LocalDateTime
     * 支持的标准时间格式为：
     * yyyyMMdd、yyyy-MM-dd、yyyy/MM/dd、yyyyMMddHHmmss、yyyy-MM-dd HH:mm:ss、yyyy/MM/dd HH:mm:ss
     * yyyy-MM-dd'T'HH:mm:ss
     *
     * @param dateTimeStr 时间格式的字符串
     * @return LocalDateTime
     */
    public static LocalDateTime parseLocalDateTime(String dateTimeStr) {
        if (StringUtils.isEmpty(dateTimeStr)) {
            return null;
        }
        LocalDateTime localDateTime;
        // “ - ” 符号分隔的年月日时间格式
        if (dateTimeStr.contains(StrPoolUtils.DASH)) {
            if (dateTimeStr.contains(StringUtils.SPACE)) {
                localDateTime = LocalDateTime.parse(dateTimeStr, DATE_TIME_FORMAT4);
            } else if (dateTimeStr.contains("T")) {
                localDateTime = LocalDateTime.parse(dateTimeStr, DATE_TIME_FORMAT6);
            } else {
                localDateTime = LocalDate.parse(dateTimeStr, DATE_FORMAT4).atStartOfDay();
            }
        }
        // “ / ” 符号分隔的年月日时间格式
        else if (dateTimeStr.contains(StrPoolUtils.SLASH)) {
            if (dateTimeStr.contains(StringUtils.SPACE)) {
                localDateTime = LocalDateTime.parse(dateTimeStr, DATE_TIME_FORMAT5);
            } else {
                localDateTime = LocalDate.parse(dateTimeStr, DATE_FORMAT6).atStartOfDay();
            }
        }
        // 无符号分隔的年月日时间格式
        else {
            if (dateTimeStr.length() == 8) {
                localDateTime = LocalDate.parse(dateTimeStr, DATE_FORMAT2).atStartOfDay();
            } else {
                localDateTime = LocalDateTime.parse(dateTimeStr, DATE_TIME_FORMAT1);
            }
        }
        return localDateTime;
    }

    /**
     * 获取无符号分隔的年月日时间格式 yyyyMMdd
     *
     * @return
     */
    public static String getDateFormat2Str(LocalDate localDate) {
        return localDateToStr(localDate, DATE_FORMAT2);
    }

    /**
     * 获取当前无符号分隔的年月日时间格式 yyyyMMdd
     *
     * @return
     */
    public static String getDateFormat2Str() {
        return localDateToStr(LocalDate.now(), DATE_FORMAT2);
    }

    /**
     * 获取当前无符号分隔的时分秒时间格式 HHmmss
     *
     * @return
     */
    public static String getTimeFormat1Str() {
        return localDateTimeToStr(LocalDateTime.now(), TIME_FORMAT1);
    }

    /**
     * 无符号分隔的时分秒时间格式 HHmmss
     *
     * @return
     */
    public static String getTimeFormat1Str(LocalDateTime localDateTime) {
        return localDateTimeToStr(localDateTime, TIME_FORMAT1);
    }

    /**
     * 获取当前 “ : ” 符号分隔的时分秒时间格式 HH:mm:ss
     *
     * @return
     */
    public static String getTimeFormat2Str() {
        return localDateTimeToStr(LocalDateTime.now(), TIME_FORMAT2);
    }

    /**
     * “ : ” 符号分隔的时分秒时间格式 HH:mm:ss
     *
     * @return
     */
    public static String getTimeFormat2Str(LocalDateTime localDateTime) {
        return localDateTimeToStr(localDateTime, TIME_FORMAT2);
    }

    /**
     * 获取当前无符号分隔的年月日时分秒时间格式 yyyyMMddHHmmss
     *
     * @return
     */
    public static String getDateTimeFormat1Str() {
        return localDateTimeToStr(LocalDateTime.now(), DATE_TIME_FORMAT1);
    }

    /**
     * 获取当前无符号分隔的年月日时分秒时间格式 yyyyMMddHHmmss
     *
     * @return
     */
    public static String getDateTimeFormat1Str(LocalDateTime localDateTime) {
        return localDateTimeToStr(localDateTime, DATE_TIME_FORMAT1);
    }

    /**
     * 获取当前“ - ” 符号分隔的年月时间格式 yyyy-MM
     *
     * @return
     */
    public static String getDateFormat3Str() {
        return localDateToStr(LocalDate.now(), DATE_FORMAT3);
    }

    /**
     * “ - ” 符号分隔的年月时间格式 yyyy-MM
     *
     * @return
     */
    public static String getDateFormat3Str(LocalDate localDate) {
        return localDateToStr(localDate, DATE_FORMAT3);
    }

    /**
     * 获取当前 “ - ” 符号分隔的年月日时间格式 yyyy-MM-dd
     *
     * @return
     */
    public static String getDateFormat4Str() {
        return localDateToStr(LocalDate.now(), DATE_FORMAT4);
    }

    /**
     * 获取当前“ - ” 符号分隔的年月日时间格式 yyyy-MM-dd
     *
     * @return
     */
    public static String getDateFormat4Str(LocalDate localDate) {
        return localDateToStr(localDate, DATE_FORMAT4);
    }

    /**
     * 获取当前“ - ” 符号分隔的年月日 “ : ” 符号分隔的时分秒时间格式 yyyy-MM-dd HH:mm:ss
     *
     * @return
     */
    public static String getDateTimeFormat4Str() {
        return localDateTimeToStr(LocalDateTime.now(), DATE_TIME_FORMAT4);
    }

    /**
     * “ - ” 符号分隔的年月日 “ : ” 符号分隔的时分秒时间格式 yyyy-MM-dd HH:mm:ss
     *
     * @return
     */
    public static String getDateTimeFormat4Str(LocalDateTime localDateTime) {
        return localDateTimeToStr(localDateTime, DATE_TIME_FORMAT4);
    }

    /**
     * 获取当前标准的 ISO 年月日时分秒时间格式 yyyy-MM-dd'T'HH:mm:ss
     *
     * @return
     */
    public static String getDateTimeFormat6Str() {
        return localDateTimeToStr(LocalDateTime.now(), DATE_TIME_FORMAT6);
    }

    /**
     * 标准的 ISO 年月日时分秒时间格式 yyyy-MM-dd'T'HH:mm:ss
     *
     * @return
     */
    public static String getDateTimeFormat6Str(LocalDateTime localDateTime) {
        return localDateTimeToStr(localDateTime, DATE_TIME_FORMAT6);
    }

    /**
     * 获取当前无符号分隔的年月日 “ : ” 符号分隔的时分秒时间格式 yyyyMMdd HH:mm:ss
     *
     * @return
     */
    public static String getDateTimeFormat2Str() {
        return localDateTimeToStr(LocalDateTime.now(), DATE_TIME_FORMAT2);
    }

    /**
     * 无符号分隔的年月日 “ : ” 符号分隔的时分秒时间格式 yyyyMMdd HH:mm:ss
     *
     * @return
     */
    public static String getDateTimeFormat2Str(LocalDateTime localDateTime) {
        return localDateTimeToStr(localDateTime, DATE_TIME_FORMAT2);
    }

    /**
     * 获取当前 “ / ” 符号分隔的月日年时间格式 MM/dd/yyyy
     *
     * @return
     */
    public static String getDateFormat7Str() {
        return localDateToStr(LocalDate.now(), DATE_FORMAT7);
    }

    /**
     * “ / ” 符号分隔的月日年时间格式 MM/dd/yyyy
     *
     * @return
     */
    public static String getDateFormat7Str(LocalDate localDate) {
        return localDateToStr(localDate, DATE_FORMAT7);
    }

    /**
     * 获取当前“ - ” 符号分隔的年月日 “ : ” 符号分隔的时分秒毫秒时间格式 yyyy-MM-dd HH:mm:ss.SSS
     *
     * @return
     */
    public static String getDateTimeFormat8Str() {
        return localDateTimeToStr(LocalDateTime.now(), DATE_TIME_FORMAT8);
    }

    /**
     * “ - ” 符号分隔的年月日 “ : ” 符号分隔的时分秒毫秒时间格式 yyyy-MM-dd HH:mm:ss.SSS
     *
     * @param localDateTime 当前时间
     * @return
     */
    public static String getDateTimeFormat8Str(LocalDateTime localDateTime) {
        return localDateTimeToStr(localDateTime, DATE_TIME_FORMAT8);
    }

    /**
     * 获取当前标准的 ISO 年月日时分秒毫秒时间格式 yyyy-MM-dd'T'HH:mm:ss.SSS
     *
     * @return
     */
    public static String getDateTimeFormat9Str() {
        return localDateTimeToStr(LocalDateTime.now(), DATE_TIME_FORMAT9);
    }

    /**
     * 标准的 ISO 年月日时分秒毫秒时间格式 yyyy-MM-dd'T'HH:mm:ss.SSS
     *
     * @param localDateTime 当前时间
     * @return
     */
    public static String getDateTimeFormat9Str(LocalDateTime localDateTime) {
        return localDateTimeToStr(localDateTime, DATE_TIME_FORMAT9);
    }

    /**
     * 获取当前时间的本周一
     *
     * @param localDate 当前时间
     * @return
     */
    public static LocalDate getWeekMonday(LocalDate localDate) {
        return localDate.with(DayOfWeek.MONDAY);
    }

    /**
     * 获取当前时间的本月最后一天
     *
     * @param localDate 当前时间
     * @return
     */
    public static LocalDate getLastDayOfMonth(LocalDate localDate) {
        return localDate.with(TemporalAdjusters.lastDayOfMonth());
    }

    /**
     * 检查当前时间的是否在两个时间范围内
     *
     * @param scopeTime   时间范围 HH:mm:ss-HH:mm:ss
     * @param compareTime
     * @return true 在范围内；false 不在范围内；
     */
    public static boolean isInScopeTime(String scopeTime, LocalDateTime compareTime) {
        String[] split = scopeTime.split("-");
        String nowDate = compareTime.toLocalDate().toString();
        LocalDateTime startTime = DateUtil.parseLocalDateTime(nowDate + " " + split[0]);
        LocalDateTime endTime = DateUtil.parseLocalDateTime(nowDate + " " + split[1]);
        // 是否在时间范围内
        return compareTime.isAfter(startTime) && compareTime.isBefore(endTime);
    }

    /**
     * 序列时间(yyyyMMdd)
     *
     * @return
     */
    public static String formatPacked() {
        long currentNanos = System.nanoTime();
        long deltaNanos = currentNanos - referenceNanoTime;
        long currentMillis = referenceMilliTime + deltaNanos / 1000000L;
        LocalDateTime dateTime = LocalDateTime.ofEpochSecond(currentMillis / 1000, 0, ZoneOffset.ofHours(8));
        return getDateFormat2Str(dateTime.toLocalDate());
    }

    public static Date toDate(LocalDateTime localDateTime) {
        return localDateTime == null ? null : Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
    }

    public static LocalDateTime toLocalDateTime(Date date) {
        return date == null ? null : date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
    }

    public static LocalDate toLocalDate(Date date) {
        return date == null ? null : date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime().toLocalDate();
    }

    public static void main(String[] args) {
        String dateTimeFormat6Str = getDateTimeFormat6Str();
        System.out.println(dateTimeFormat6Str);

    }
}
